package com.jzo2o.market.task;

import cn.hutool.core.util.ObjectUtil;
import com.jzo2o.api.customer.CommonUserApi;
import com.jzo2o.api.customer.dto.response.CommonUserResDTO;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.DateUtils;
import com.jzo2o.market.constants.RedisConstants;
import com.jzo2o.market.enums.CouponStatusEnum;
import com.jzo2o.market.model.domain.Activity;
import com.jzo2o.market.model.domain.Coupon;
import com.jzo2o.market.service.IActivityService;
import com.jzo2o.market.service.ICouponService;
import com.jzo2o.redis.model.SyncMessage;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * TODO
 *
 * @Author whx
 * @Date 2024/12/22 12:04
 */
@Component
@Slf4j
public class SyncMessageTask {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private ApplicationContext applicationContext;

    @Async
    public void batchHandleSyncMessage(Long index){
        //执行任务
        log.info("{}执行任务:{}",Thread.currentThread().getName(),index);
        String redisKey = String.format(RedisConstants.RedisKey.COUPON_SEIZE_SYNC_QUEUE_NAME, index);

        //基于队列名获取锁实例
        RLock lock = redissonClient.getLock("LOCK:" + redisKey);

        List<SyncMessage<Object>> syncMessageList = null;

        try {
            boolean result = lock.tryLock(3, -1, TimeUnit.SECONDS);
            if(!result){
                log.error("线程：{}加锁失败，" , Thread.currentThread().getName());
            }else {
                log.info("线程：{}加锁成功，" , Thread.currentThread().getName());

                syncMessageList = this.batchGetSyncMessage(redisKey);

                if(CollUtils.isNotEmpty(syncMessageList)){
                    syncMessageList.forEach(System.out::println);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            // 插入
            SyncMessageTask owner = applicationContext.getBean(SyncMessageTask.class);
            owner.syncMessageToDB(syncMessageList);

            // 删除redis数据
            syncMessageList.forEach(x->{
                redisTemplate.opsForHash().delete(redisKey, x.getKey());
            });

            lock.unlock();
        }
    }

    @Autowired
    private CommonUserApi commonUserApi;

    @Autowired
    private IActivityService activityService;

    @Autowired
    private ICouponService couponService;

    @Transactional(rollbackFor = Exception.class)
    public void syncMessageToDB(List<SyncMessage<Object>> syncMessageList) {

        for (SyncMessage<Object> syncMessage : syncMessageList) {
            Long userId = Long.valueOf(syncMessage.getKey());
            Long activityId = Long.valueOf(syncMessage.getValue().toString());

            CommonUserResDTO userInfo = commonUserApi.findById(userId);
            if(ObjectUtil.isEmpty(userInfo)){
                throw new ForbiddenOperationException("用户不存在");
            }

            Activity activity = activityService.getById(activityId);
            if(ObjectUtil.isEmpty(activity)){
                throw new ForbiddenOperationException("活动不存在");
            }

            // 封装Coupon对象
            Coupon coupon = new Coupon();
            coupon.setName(activity.getName());
            coupon.setUserId(userId);
            coupon.setUserName(userInfo.getNickname());
            coupon.setUserPhone(userInfo.getPhone());
            coupon.setActivityId(activityId);
            coupon.setType(activity.getType());
            coupon.setDiscountRate(activity.getDiscountRate());
            coupon.setAmountCondition(activity.getAmountCondition());
            coupon.setValidityTime(DateUtils.now().plusDays(activity.getValidityDays()));
            coupon.setStatus(CouponStatusEnum.NO_USE.getStatus());

            // 新增
            boolean result = couponService.save(coupon);
            if(!result){
                throw new ForbiddenOperationException("新增领取记录失败");
            }

            // 更新活动库存
            boolean resultForActivity = activityService.decrementStockNum(activityId);
            if(!resultForActivity){
                throw new ForbiddenOperationException("更新活动库存失败");
            }
        }

    }

    @Autowired
    private RedisTemplate redisTemplate;


    public List<SyncMessage<Object>> batchGetSyncMessage(String redisKey){
        Cursor<Map.Entry<String, Object>> cursor = redisTemplate.opsForHash().scan(redisKey, ScanOptions.scanOptions().count(10).build());

        if(cursor==null) {
            return CollUtils.emptyList();
        }

        List<SyncMessage<Object>> syncMessageList = cursor.stream().map(
                        x -> SyncMessage.builder()
                        .key(x.getKey())
                        .value(x.getValue())
                        .build()
                ).collect(Collectors.toList());

        cursor.close();

        return syncMessageList;
    }

}
